package com.knife.oauth.security.customer.chain;

import com.knife.oauth.security.customer.entity.CheckResponse;
import com.knife.oauth.security.customer.entity.CheckState;
import com.knife.oauth.security.customer.entity.RequestContext;
import com.knife.oauth.security.customer.entity.ResponseContext;
import com.knife.oauth.security.customer.filter.KnifeHelperFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 执行自定义过滤器
 *
 * @author： 76875
 * @date： 2022/4/14 星期四 14:41
 * @description：
 * @modifiedBy：
 * @version: 1.0
 */
@Slf4j
@SuppressWarnings("ALL")
public class KnifeHelperChain {

    private List<KnifeHelperFilter> knifeHelperFilters;

    private static final Set<CheckState> UNAUTHORIZED = new HashSet<>(Arrays.asList(
            CheckState.PERMISSION_ACCESS_TOKEN_NULL,
            CheckState.PERMISSION_ACCESS_TOKEN_INVALID,
            CheckState.PERMISSION_ACCESS_TOKEN_EXPIRED,
            CheckState.PERMISSION_GET_USE_DETAIL_FAILED
    ));

    public KnifeHelperChain(Optional<List<KnifeHelperFilter>> optionalHelperFilters) {
        this.knifeHelperFilters = optionalHelperFilters.orElseGet(Collections::emptyList)
                .stream()
                .sorted(Comparator.comparing(KnifeHelperFilter::filterOrder))
                .collect(Collectors.toList());
    }


    public ResponseContext doFilter(RequestContext request) {
        CheckResponse checkResponse = request.response;
        ResponseContext responseContext = new ResponseContext();
        try {
            for (KnifeHelperFilter knifeHelperFilter : knifeHelperFilters) {
                if (knifeHelperFilter.shouldFilter(request) && !knifeHelperFilter.run(request)) {
                    break;
                }
            }
        } catch (Exception e) {
            checkResponse.setStatus(CheckState.EXCEPTION_GATEWAY_HELPER);
            checkResponse.setMessage("gateway helper error happened: " + e.toString());
            log.info("Check permission error", e);
        }
        // 自定义状态转变为httpStatus
        if (checkResponse.getStatus().getValue() < HttpStatus.MULTIPLE_CHOICES.value()) {
            responseContext.setHttpStatus(HttpStatus.OK);
            log.debug("Request 200, context: {}", request);
        } else if (UNAUTHORIZED.contains(checkResponse.getStatus())) {
            responseContext.setHttpStatus(HttpStatus.UNAUTHORIZED);
            log.info("Request 401, context: {}", request);
        } else if (checkResponse.getStatus().getValue() < HttpStatus.INTERNAL_SERVER_ERROR.value()) {
            responseContext.setHttpStatus(HttpStatus.FORBIDDEN);
            log.info("Request 403, context: {}", request);
        } else {
            responseContext.setHttpStatus(HttpStatus.INTERNAL_SERVER_ERROR);
            log.info("Request 500, context: {}", request);
        }

        if (checkResponse.getMessage() != null) {
            responseContext.setRequestMessage(checkResponse.getMessage());
        }
        responseContext.setJwtToken(checkResponse.getJwt());
        responseContext.setRequestStatus(checkResponse.getStatus().name());
        responseContext.setRequestCode(checkResponse.getStatus().getCode());
        return responseContext;
    }


}
